package com.senseauto.openglbitmap;

import android.opengl.GLES20;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

public class BitmapSquare {
    /**
     * 顶点着色器代码;
     */
    private static String vertexShaderCode =
            // 等待输入的纹理顶点坐标
            "attribute vec4 inputTextureCoordinate;" +
                    " varying vec2 textureCoordinate;" +
                    "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = vPosition;" +
                    "textureCoordinate = inputTextureCoordinate.xy;" +
                    "}";

    /**
     * 片段着色器代码
     */
    private static String fragmentShaderCode =
            "varying highp vec2 textureCoordinate;" +
                    "uniform sampler2D inputImageTexture;" +
                    "void main() {" +
                    // 将2D纹理inputImageTexture和纹理顶点坐标通过texture2D计算后传给片段着色器
                    "  gl_FragColor = texture2D(inputImageTexture, textureCoordinate);" +
                    "}";

    public BitmapSquare() {
        init();
    }

    // 每个顶点的坐标数
    private int COORDS_PER_VERTEX = 3;
    // 每个纹理顶点的坐标数
    private int COORDS_PER_TEXTURE_VERTEX = 2;
    // 顶点的坐标
    private float[] squareCoords = new float[]{
            -0.5f, 0.5f, 0.0f,      // top left
            -0.5f, -0.5f, 0.0f,      // bottom left
            0.5f, -0.5f, 0.0f,      // bottom right
            0.5f, 0.5f, 0.0f       // top right
    };
    // 顶点所对应的纹理坐标
    private float[] texVertex = new float[]{
            0f, 0f,      // top left
            0f, 1f,      // bottom left
            1f, 1f,       // bottom right
            1f, 0f     // top right
    };
    // 四个顶点的缓冲数组
    private FloatBuffer vertexBuffer ;

    // 四个顶点的绘制顺序数组
    private short[] drawOrder = new short[]{0, 1, 2, 0, 2, 3};

    // 四个顶点绘制顺序数组的缓冲数组
    private ShortBuffer drawListBuffer;


    // 四个纹理顶点的缓冲数组
    private FloatBuffer texVertexBuffer;


    private int vPMatrixHandle = 0;
    /**
     * 着色器程序ID引用
     */
    private int mProgram;

    public void init() {
        // 编译顶点着色器和片段着色器
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
        // glCreateProgram函数创建一个着色器程序，并返回新创建程序对象的ID引用
        mProgram = GLES20.glCreateProgram();

        // 把顶点着色器添加到程序对象
        GLES20.glAttachShader(mProgram, vertexShader);
        // 把片段着色器添加到程序对象
        GLES20.glAttachShader(mProgram, fragmentShader);
        // 连接并创建一个可执行的OpenGL ES程序对象
        GLES20.glLinkProgram(mProgram);

        vertexBuffer = ByteBuffer.allocateDirect(squareCoords.length * 4).order(ByteOrder.nativeOrder()) .asFloatBuffer();
        vertexBuffer. put(squareCoords);
        vertexBuffer. position(0);

        drawListBuffer = ByteBuffer.allocateDirect(drawOrder.length *2).order(ByteOrder.nativeOrder()).asShortBuffer();
        drawListBuffer. put(drawOrder);
        drawListBuffer.position(0);

        texVertexBuffer = ByteBuffer.allocateDirect(texVertex.length * 4).order(ByteOrder.nativeOrder()) .asFloatBuffer();
        texVertexBuffer. put(texVertex);
        texVertexBuffer. position(0);

    }

    private int loadShader(int type, String shaderCode) {
        // glCreateShader函数创建一个顶点着色器或者片段着色器,并返回新创建着色器的ID引用
        int shader = GLES20.glCreateShader(type);
        // 把着色器和代码关联,然后编译着色器
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

    private int vertexStride = COORDS_PER_VERTEX * 4;
    private int textVertexStride = COORDS_PER_TEXTURE_VERTEX * 4;

    public void draw(int textureID) {
        // 激活着色器程序 Add program to OpenGL ES environment
        GLES20.glUseProgram(mProgram);
        // 获取顶点着色器中的vPosition变量(因为之前已经编译过着色器代码,所以可以从着色器程序中获取);用唯一ID表示
        int position = GLES20.glGetAttribLocation(mProgram, "vPosition");
        // 允许操作顶点对象position
        GLES20.glEnableVertexAttribArray(position);
        // 将顶点数据传递给position指向的vPosition变量;将顶点属性与顶点缓冲对象关联
        GLES20.glVertexAttribPointer(
                position, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
                false, vertexStride, vertexBuffer
        );
        // 激活textureID对应的纹理单元
        GLES20.glActiveTexture(textureID);
        // 绑定纹理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
        // 获取顶点着色器中的inputTextureCoordinate变量(纹理坐标);用唯一ID表示
        int textureCoordinate = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");
        // 允许操作纹理坐标inputTextureCoordinate变量
        GLES20.glEnableVertexAttribArray(textureCoordinate);
        // 将纹理坐标数据传递给inputTextureCoordinate变量
        GLES20.glVertexAttribPointer(
                textureCoordinate, COORDS_PER_TEXTURE_VERTEX, GLES20.GL_FLOAT,
                false, textVertexStride, texVertexBuffer
        );
        // 按drawListBuffer中指定的顺序绘制四边形
        GLES20.glDrawElements(
                GLES20.GL_TRIANGLE_STRIP, drawOrder.length,
                GLES20.GL_UNSIGNED_SHORT, drawListBuffer
        );
        // 操作完后,取消允许操作顶点对象position
        GLES20.glDisableVertexAttribArray(position);
        GLES20.glDisableVertexAttribArray(textureCoordinate);
    }
}